﻿using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.AutoMapper;
using Abp.Linq.Extensions;
using Abp.Domain.Repositories;
using Abp.IdentityFramework;
using Abp.UI;
using Microsoft.AspNet.Identity;
using SingleUserMall.Authorization;
using SingleUserMall.Authorization.Roles;
using SingleUserMall.Authorization.Users;
using SingleUserMall.Common;
using SingleUserMall.Roles.Form;
using SingleUserMall.Roles.VO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace SingleUserMall.Roles
{
    [AbpAuthorize]
    public class RoleManageAppService : SingleUserMallAppServiceBase, IRoleManageAppService
    {
        private readonly RoleManager _roleManager;
        private readonly UserManager _userManager;
        private readonly IRepository<User, long> _userRepository;
        private readonly IRepository<UserRole, long> _userRoleRepository;
        private readonly IRepository<Role> _roleRepository;

        public RoleManageAppService(
            IRepository<Role> repository,
            RoleManager roleManager,
            UserManager userManager,
            IRepository<User, long> userRepository,
            IRepository<UserRole, long> userRoleRepository,
            IRepository<Role> roleRepository)
        {
            _roleManager = roleManager;
            _userManager = userManager;
            _userRepository = userRepository;
            _userRoleRepository = userRoleRepository;
            _roleRepository = roleRepository;
        }



        private Task<List<long>> GetUsersInRoleAsync(string roleName)
        {
            var users = (from user in _userRepository.GetAll()
                         join userRole in _userRoleRepository.GetAll() on user.Id equals userRole.UserId
                         join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id
                         where role.Name == roleName
                         select user.Id).Distinct().ToList();

            return Task.FromResult(users);
        }

        public async Task<ListResultDto<PermissionVO>> GetAllPermissionsAsync()
        {
            var permissions = PermissionManager.GetAllPermissions();

            return await Task.FromResult(new ListResultDto<PermissionVO>(
                ObjectMapper.Map<List<PermissionVO>>(permissions)
            ));
        }
        public async Task<ListResultDto<RoleVO>> GetRolesAsync(RoleSearchForm form)
        {
            var roles = _roleRepository.GetAll()
                .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.Name.Contains(form.Keywords));
            var result = await roles.ToListResultDtoAsync<Role, RoleVO>();
            foreach (var item in result.Items)
            {
                item.Permissions = (await _roleManager.GetGrantedPermissionsAsync(item.Id)).Select(x => x.Name).ToList();
            }
            return result;
        }

        public async Task<RoleVO> GetRoleAsync(SingleId<int> form)
        {
            var role = await _roleRepository.FirstOrDefaultAsync(form.Id);
            var result = role.ToVO<Role, RoleVO>();
            result.Permissions = (await _roleManager.GetGrantedPermissionsAsync(result.Id)).Select(x => x.Name).ToList();
            return result;
        }

        public async Task SaveRoleAsync(RoleForm form)
        {
            try
            {
                var role = await _roleRepository.FirstOrDefaultAsync(form.Id);
                if (role != null)
                {

                    role.Name = form.Name;
                    role.DisplayName = form.Name;
                    await _roleRepository.UpdateAsync(role);
                }
                else
                {
                    role = new Role();
                    role.Name = form.Name;
                    role.DisplayName = form.Name;
                    await _roleRepository.InsertAsync(role);
                }
                CurrentUnitOfWork.SaveChanges();
                var permissions = PermissionManager.GetAllPermissions().Where(x => form.Permissions.Contains(x.Name)).ToList();
                await _roleManager.SetGrantedPermissionsAsync(role, permissions);
            }
            catch (Exception ex)
            {
                throw new UserFriendlyException(ex.Message);
            }
        }

        public async Task RemoveRoleAsync(SingleId<int> form)
        {
            var role = _roleRepository.FirstOrDefault(form.Id);
             _userRoleRepository.Delete(x => x.RoleId == role.Id);
             _roleRepository.Delete(form.Id);
        }
    }
}